﻿//----------------------------------------------------------------
// Desc: 
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2012-04-13
//
// Update Date : 
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


//----------------------------------------------------------------
// 自动类对象或者结构体对象创建库
// ._BaseTy 是该类或者结构体的基类
// ._TyID 是用于ID处理的类型，且由它书写的成员变量名为nTypeID
//        如：'FAutoClassFactory < MyClassBase, DWORD >' 和 'DWORD nTypeID;'
// 使用方法：
//   1. FAutoClassFactory继承使用，也可以作为某个成员变量使用
//   2. 调用Register注册指定的ID生成指定的类型，如ClassA的id为0，ClassB的id为1。
//   3. 调用NewClass分配，如传0创建ClassA，传1创建ClassB。
//   4. 调用DelClass释放分配出来的对象
//----------------------------------------------------------------
template < typename _BaseTy, typename _TyID >
class FAutoClassFactory : public IFMemObject
{
public:
    // 函数类型
    typedef _BaseTy* (*new_func)();
    typedef void (*constructor_func)(_BaseTy* p);
    typedef void (*destructor_func)(_BaseTy* p);
    struct OBJECT_INSTANCE
    {
		_TyID id;
        size_t size;
        new_func p_new;
        constructor_func p_constructor;
        destructor_func p_destructor;
    };
    // 容器
    typedef FVector< OBJECT_INSTANCE > fv_obj_instance;
    typedef FVector< _BaseTy* > fv_obj_recycle;

    fv_obj_instance vObjInstance;   // 对象分配库
    fv_obj_recycle vRecycle;        // 回收站

    //
    FAutoClassFactory()
    {
		vObjInstance.reserve(64);
        vRecycle.reserve(128);
    }
    // 析构
    virtual~FAutoClassFactory()
    {
        for (size_t i = 0; i < vRecycle.size(); ++i)
            DelObject(vRecycle[i]);
        vRecycle.clear();
    }
    virtual void DelObject(_BaseTy*& p)
    {
        FDel(p);
    }
    // 注册类或者结构体
    template < typename _DeriveTy >
    void Register(_TyID id)
    {
        FASSERT(!FindClass(id), _T("警告：重复注册对象"));
        OBJECT_INSTANCE& op = *FindClass(id, true);
        op.size = sizeof(_DeriveTy);
        op.p_new = _new_template<_DeriveTy>;
        op.p_constructor = _constructor_template<_DeriveTy>;
        op.p_destructor = _destructor_template<_DeriveTy>;
    }
    // 创建类或者结构体
    _BaseTy* NewClass(_TyID id)
    {
		OBJECT_INSTANCE* find_op = FindClass(id);
        if (!find_op)
            return 0;
        _BaseTy* p = FindRecycle(id);
        if (p)
        {
            if (p->nTypeID == id)
            {
                find_op->p_constructor(p);
                return p;
            }
            DelObject(p);
        }
        p = find_op->p_new();
        if (!p)
            return 0;
        if (p->nTypeID == id)
            return p;
        DelObject(p);
        return 0;
    }
    // 释放类或者结构体
    void DelClass(_BaseTy* p, bool use_recycle = true)
    {
        if (!p)
            return;
		OBJECT_INSTANCE* find_op = FindClass(p->nTypeID);
        if (find_op)
        {
            if (use_recycle)
            {
                find_op->p_destructor(p);
                vRecycle.push_back(p);
            }
            else
                DelObject(p);
        }
        else
        {
            FASSERT_STR(_T("请求删除一个没有注册的对象"));
            DelObject(p);
        }
    }
    // 取得该类或者结构体的尺寸（通常用于结构体，便于计算存文件时所需大小）
    size_t GetClassSize(_TyID id)
    {
        OBJECT_INSTANCE* hobj = FindClass(id);
        return hobj ? hobj->size : 0;
    }
	// 查询对象
	OBJECT_INSTANCE* FindClass(_TyID id, bool add = false)
	{
		for (size_t i = 0; i < vObjInstance.size(); ++i)
		{
			if (vObjInstance[i].id == id)
				return &vObjInstance[i];
		}
		if (add)
		{
			OBJECT_INSTANCE to;
			to.id = id;
			vObjInstance.push_back(to);
			return &vObjInstance.back();
		}
		return 0;
    }

private:
    // 函数实体地址
    template < typename _DeriveTy >
    static _BaseTy* _new_template()
    {
        return FNew(_DeriveTy);
    }
    template < typename _DeriveTy >
    static void _constructor_template(_BaseTy* p)
    {
        FNewPP(p) _DeriveTy;
    }
    template < typename _DeriveTy >
    static void _destructor_template(_BaseTy* p)
    {
        ((_DeriveTy*)p)->~_DeriveTy();
    }

protected:
    _BaseTy* FindRecycle(_TyID id)
    {
        for (size_t i = 0; i < vRecycle.size(); ++i)
        {
            if (vRecycle[i]->nTypeID != id)
                continue;
            _BaseTy* ret = vRecycle[i];
            vRecycle.erase(i);
            return ret;
        }
        return 0;
    }
};
